function ind=genetic_op(subproblems, index)
%GENETIC_OP: The function implements the DE operation to generate new
% individuals from the subproblems and its neighbours.

%   subproblems : is all the subproblems.
%   index       : the index of the subproblem need to handle.
    global params;
    neighbourindex = subproblems(index).neighbour;
    
    %The random draw from the neighbours.
    nsize = length(neighbourindex);
    si = ones(1,2)*index;
    
    si(1)=neighbourindex(ceil(rand*nsize));
    while si(1)==index
        si(1)=neighbourindex(ceil(rand*nsize));
    end
    
    si(2)=neighbourindex(ceil(rand*nsize));
    while si(2)==index || si(2)==si(1)
        si(2)=neighbourindex(ceil(rand*nsize));
    end
     
    %retrieve the individuals.
    ind1 = []; ind2 = [];
    if rand < params.pc
        ind1 = cross_merge_op(subproblems(si(1)), subproblems(si(2)));
    else
        %ind2 = mutation_based_neighbors(subproblems(index));
        ind2 = mutation_based_similarity(subproblems(index));
    end   
    ind = [ind1,ind2];
end

%%
function [ y ] = cross_merge_op( ind1, ind2 )
%Cross-merging Operator based on local node sets.
    label1 = ind1.net_data.label;
    label2 = ind2.net_data.label;
    y = [ind1.net_data, ind2.net_data];    
    pos1 = ceil(rand*length(label1));
    pos2 = ceil(rand*length(label2));
    node_c1 = label1(pos1);        
    node_c2 = label2(pos2);        
    if (pos1 == pos2)&&(node_c1 == node_c2)
        y = [];
        return
    elseif (pos1 == pos2) && (node_c1 ~= node_c2)      
        index1 = (label1 == node_c1);
        index2 = (label2 == node_c2);
        label1(index2) = node_c2;
        label2(index1) = node_c1;
    else
        index1 = (label1 == node_c2);
        index2 = (label2 == node_c1);
        label1(index1) = node_c1;
        label2(index2) = node_c2;
    end
    
    label1 = decode(label1);
    label2 = decode(label2);
    y(1).label = label1;
    y(2).label = label2;

end

%%
function [ y ] = mutation_based_neighbors(ind)
%Mutation operator based on the neighbors of the selected node.
data = ind.net_data;
label = data.label;
boundary_nodes = find_bounday_nodes(data);

overlapping_nodes = boundary_nodes.overlapping_nodes;
over_number = length(overlapping_nodes);

if over_number ~= 0
    pos = ceil(rand*over_number);
    select_nodes = overlapping_nodes(pos);
    neighbors = data.adjacent_nodes.pos_adjacent{select_nodes};   
    nodes_in_other_community = (label(neighbors) ~= label(select_nodes));
    % testing both two neighbors have different labels with selected nodes.
    if sum(nodes_in_other_community) == 1
        label(select_nodes) = label(neighbors(nodes_in_other_community));
    elseif sum(nodes_in_other_community) == 2
        random_one = ceil(rand*2);
        label(select_nodes) = label(neighbors(random_one));
    else
        error('The function of find_boundary_nodes is wrong with something.\n')
    end
%     random_one = ceil(rand*length(neighbors));
%     label(select_nodes) = label(neighbors(random_one));
else
    nonoverlapping_nodes = boundary_nodes.nonoverlapping_nodes;
    if ~isempty(nonoverlapping_nodes)
        pos = ceil(rand*length(nonoverlapping_nodes));
        select_nodes = nonoverlapping_nodes(pos);
        neighbors = data.adjacent_nodes.pos_adjacent{select_nodes};
        nodes_in_other_community = find(label(neighbors) ~= label(select_nodes));
        random_nodes_index = ceil(rand*length(nodes_in_other_community));
        label(select_nodes) = label(nodes_in_other_community(random_nodes_index));
    end
end

data.label = label; 
y = data;
end

